<template>
  <div class="liteflow-editor-container" :class="className" ref="wrapperRef">
    <div class="liteflow-editor-graph" ref="graphRef"></div>
    <div class="liteflow-editor-mini-map" ref="miniMapRef"></div>
    <Breadcrumb v-if="flowGraph" :flowGraph="flowGraph" />
    <FlowGraphContextMenu 
      v-if="flowGraph" 
      :flowGraph="flowGraph" 
      v-bind="contextMenuInfo" 
    />
    <FlowGraphContextPad 
      v-if="flowGraph" 
      :flowGraph="flowGraph" 
      v-bind="contextPadInfo" 
    />
    <slot></slot>
  </div>
</template>

<script>
import { Graph } from '@antv/x6';
import Layout from './panels/layout/index.vue';
import SideBar from './panels/sideBar/index.vue';
import ToolBar from './panels/toolBar/index.vue';
import SettingBar from './panels/settingBar/index.vue';
import Breadcrumb from './panels/breadcrumb/index.vue';
import FlowGraphContextMenu from './panels/flowGraph/contextMenu/index.vue';
import FlowGraphContextPad from './panels/flowGraph/contextPad/index.vue';
import createFlowGraph from './panels/flowGraph/createFlowGraph';
import { forceLayout } from './common/layout';
import { useModel } from './hooks/useModel';
import { history } from './hooks/useHistory';
import ELBuilder from './model/builder';
import { setModel } from './hooks/useModel';
import { MIN_ZOOM } from './constant';
import '@antv/x6/dist/x6.css';

export default {
  name: 'LiteFlowEditor',
  components: {
    Layout,
    SideBar,
    ToolBar,
    SettingBar,
    Breadcrumb,
    FlowGraphContextMenu,
    FlowGraphContextPad
  },
  props: {
    className: {
      type: String,
      default: ''
    },
    onReady: {
      type: Function,
      default: null
    },
    widgets: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      flowGraph: null,
      contextMenuInfo: {
        x: 0,
        y: 0,
        scene: 'blank',
        visible: false
      },
      contextPadInfo: {
        x: 0,
        y: 0,
        scene: 'append',
        visible: false
      },
      currentEditor: {
        getGraphInstance: () => this.flowGraph,
        toJSON: () => useModel().toJSON(),
        fromJSON: (data) => {
          const model = ELBuilder.build(data || {});
          setModel(model);
          history.cleanHistory();
          this.flowGraph?.zoomToFit({ minScale: MIN_ZOOM, maxScale: 1 });
        }
      }
    };
  },
  mounted() {
    this.initFlowGraph();
    this.bindEvents();
  },
  beforeDestroy() {
    this.unbindEvents();
  },
  methods: {
    initFlowGraph() {
      if (this.$refs.graphRef) {
        this.flowGraph = createFlowGraph(this.$refs.graphRef);
        
        if (this.onReady) {
          this.onReady(this.flowGraph);
        }
      }
    },
    bindEvents() {
      window.addEventListener('resize', this.handleResize);
      
      if (this.flowGraph) {
        this.flowGraph.on('graph:showContextMenu', this.showContextMenu);
        this.flowGraph.on('graph:hideContextMenu', this.hideContextMenu);
        this.flowGraph.on('graph:showContextPad', this.showContextPad);
        this.flowGraph.on('graph:hideContextPad', this.hideContextPad);
        this.flowGraph.on('model:change', this.handleModelChange);
      }
    },
    unbindEvents() {
      window.removeEventListener('resize', this.handleResize);
      
      if (this.flowGraph) {
        this.flowGraph.off('graph:showContextMenu', this.showContextMenu);
        this.flowGraph.off('graph:hideContextMenu', this.hideContextMenu);
        this.flowGraph.off('graph:showContextPad', this.showContextPad);
        this.flowGraph.off('graph:hideContextPad', this.hideContextPad);
        this.flowGraph.off('model:change', this.handleModelChange);
      }
    },
    handleResize() {
      requestAnimationFrame(() => {
        if (this.flowGraph && this.$refs.wrapperRef) {
          const width = this.$refs.wrapperRef.clientWidth;
          const height = this.$refs.wrapperRef.clientHeight;
          this.flowGraph.resize(width, height);
        }
      });
    },
    showContextMenu(info) {
      this.flowGraph?.lockScroller();
      this.contextMenuInfo = { ...info, visible: true };
    },
    hideContextMenu() {
      this.flowGraph?.unlockScroller();
      this.contextMenuInfo = { ...this.contextMenuInfo, visible: false };
    },
    showContextPad(info) {
      this.flowGraph?.lockScroller();
      this.contextPadInfo = { ...info, visible: true };
    },
    hideContextPad() {
      this.flowGraph?.unlockScroller();
      this.contextPadInfo = { ...this.contextPadInfo, visible: false };
    },
    handleModelChange() {
      if (this.flowGraph) {
        const model = useModel();
        const modelJSON = model.toCells();
        this.flowGraph.scroller.disableAutoResize();
        this.flowGraph.startBatch('update');
        this.flowGraph.resetCells(modelJSON);
        forceLayout(this.flowGraph);
        this.flowGraph.stopBatch('update');
        this.flowGraph.scroller.enableAutoResize();
        this.flowGraph.trigger('model:changed');
      }
    }
  }
};
</script>

<style lang="less" scoped>
.liteflow-editor-container {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  flex-direction: column;
}

.liteflow-editor-graph {
  flex: 1;
  position: relative;
}

.liteflow-editor-mini-map {
  position: absolute;
  bottom: 20px;
  right: 20px;
  width: 200px;
  height: 150px;
  border: 1px solid #d9d9d9;
  background: #fff;
}
</style> 